package org.fixies.spreadsheet;

import org.fixies.utils.BinaryUtils;
import org.fixies.utils.DateUtils;

import java.math.BigDecimal;
import java.util.Date;

/**
 * セル
 *
 * @author Kawasaki
 */
public class Cell implements CharSequence {

    /** 元の文字列 */
    private final String orig_;

    /** 親の行 */
    private final Row parent_;

    /** ID */
    private final int id_;

    /**
     * コンストラクタ
     *
     * @param orig      元の行
     * @param parent    親の行
     * @param cellIndex セルのインデックス
     */
    public Cell(String orig, Row parent, int cellIndex) {
        orig_ = orig == null ? "" : orig;
        parent_ = parent;
        id_ = cellIndex;
    }


    public String asString() {
        return orig_;
    }

    public BigDecimal asBigDecimal() {
        BigDecimal b = null;
        try {
            b = new BigDecimal(orig_);
        } catch (NumberFormatException e) {
            handleException(e);
        }
        return b;
    }

    public byte asByte() {
        String str = orig_.startsWith("0x") ? orig_.substring(2) : orig_;
        byte b = 0;
        try {
            b = Byte.parseByte(str, 16);
        } catch (NumberFormatException e) {
            handleException(e);
        }
        return b;
    }

    public byte[] asBytes() {
        byte[] b = null;
        try {
            b = BinaryUtils.hexToBytes(orig_);
        } catch (NumberFormatException e) {
            handleException(e);
        }
        return b;
    }

    public Date asDate() {
        Date date = null;
        try {
            date = DateUtils.convertToDate(orig_);
        } catch (IllegalArgumentException e) {
            handleException(e);
        }
        return date;
    }

    public double asDouble() {
        double d = 0;
        try {
            d = Double.parseDouble(orig_);
        } catch (NumberFormatException e) {
            handleException(e);
        }
        return d;
    }

    public float asFloat() {
        float f = 0;
        try {
            f = Float.parseFloat(orig_);
        } catch (NumberFormatException e) {
            handleException(e);
        }
        return f;
    }

    public int asInt() {
        int i = 0;
        try {
            i = Integer.parseInt(orig_);
        } catch (NumberFormatException e) {
            handleException(e);
        }
        return i;
    }

    public long asLong() {
        long l = 0L;
        try {
            l = Long.parseLong(orig_);
        } catch (NumberFormatException e) {
            handleException(e);
        }
        return l;
    }

    public short asShort() {
        short s = 0;
        try {
            s = Short.parseShort(orig_);
        } catch (NumberFormatException e) {
            handleException(e);
        }
        return s;
    }

    public boolean asBoolean() {
        return Boolean.parseBoolean(orig_);
    }


    /** {@inheritDoc} */
    @Override
    protected Object clone() {
        return this;
    }

    /** {@inheritDoc} */
    @Override
    public boolean equals(Object obj) {
        if (obj == null) return false;
        if (!(obj instanceof Cell)) {
            return false;
        }
        return orig_.equals(((Cell) obj).asString());
    }

    /** {@inheritDoc} */
    @Override
    public int hashCode() {
        return orig_.hashCode();
    }

    /** {@inheritDoc} */
    @Override
    public String toString() {
        return orig_;
    }

    public String getOrigin() {
        return parent_.getOrigin() + ", Column=[" + id_ + "]";
    }

    private void handleException(Exception cause) throws InvalidDataException {
        String msg = getOrigin() + " value =[" + orig_ + "]";
        throw new InvalidDataException(msg, cause);
    }

    public char charAt(int index) {
        return asString().charAt(index);
    }

    public int length() {
        return asString().length();
    }

    public CharSequence subSequence(int start, int end) {
        return asString().subSequence(start, end);
    }


    public String asStringOrNull() {
        return isNull() ? null : orig_;
    }

    public boolean isEmpty() {
        return orig_.isEmpty();
    }

    public boolean isNull() {
        return orig_.equals("null");
    }
}
